package mx.com.zl0.util;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.datatype.XMLGregorianCalendar;

public class Util {

	public static String formatDate(String format, Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}

	public static String formatDate(Date date) {
		return formatDate("dd/MM/yyyy", date);
	}

	public static String getSpecialTimestamp(Long seconds) {
		if(seconds == null){
			return null;
		}
		Long horas = TimeUnit.SECONDS.toHours(seconds);
		Long minutos = TimeUnit.SECONDS.toMinutes(seconds)
				- TimeUnit.HOURS.toMinutes(horas);
		Long segundos = seconds - TimeUnit.HOURS.toSeconds(horas)
				- TimeUnit.MINUTES.toSeconds(minutos);

		return String.format("%02d:%02d:%02d", horas, minutos, segundos);
	}

	public static Date startOfDay(Date date) {
		GregorianCalendar gc = new GregorianCalendar();
		gc.setTime(date);
		gc.set(GregorianCalendar.HOUR, 0);
		gc.set(GregorianCalendar.MINUTE, 0);
		gc.set(GregorianCalendar.SECOND, 0);
		gc.set(GregorianCalendar.MILLISECOND, 0);
		return gc.getTime();
	}

	public static String formatXMLGregorianCalendar(
			XMLGregorianCalendar XMLGregorianCalendar) {
		if(XMLGregorianCalendar==null){
			return null;
		}
		return formatDate(XMLGregorianCalendar.toGregorianCalendar().getTime());
	}

	public static String tiempoAsignacionCompareToDay(Date fechaCompare) {
		long MILLSECS_PER_HORA = 3600000;
		long HORAS_PER_DIA = 24;
		long DIAS_PER_MES = 30;
		long MESES_PER_YEAR = 12;

		long horasDif = (new Date().getTime() - fechaCompare.getTime())
				/ MILLSECS_PER_HORA;

		long horasMod = horasDif % HORAS_PER_DIA;

		long diasDif = horasDif / HORAS_PER_DIA;

		long horas = horasMod;

		long diasMod = diasDif % DIAS_PER_MES;

		long mesesDif = diasDif / DIAS_PER_MES;

		long dias = diasMod;

		long mesesMod = mesesDif % MESES_PER_YEAR;

		long yearDif = mesesDif / MESES_PER_YEAR;

		long mes = mesesMod;

		String tiempoAsignacion = "";

		if (yearDif > 0) {
			tiempoAsignacion += yearDif + " Año(s) ";
		}

		if (mes > 0 && mes < 12) {
			tiempoAsignacion += mes + " Mes(es) ";
		}

		if (dias > 0 && dias < 30) {
			tiempoAsignacion += dias + " Dia(s) ";
		}

		if (horas >= 0) {
			tiempoAsignacion += horas + " Hora(s) ";
		}

		return tiempoAsignacion;
	}
	
	public static String tiempoEjecucion(Date fechaCompare) {
		long MILLSECS_PER_SEGUNDO = 1000;
		long SEGUNDOS_PER_MINUTO = 60;
		long MINUTOS_PER_HORA = 60;
		long HORAS_PER_DIA = 24;
		long DIAS_PER_MES = 30;
		long MESES_PER_YEAR = 12;
		
		long segundosDif = (new Date().getTime() - fechaCompare.getTime())
		/ MILLSECS_PER_SEGUNDO;
		
		long segundosMod = segundosDif % SEGUNDOS_PER_MINUTO;
		
		long minutosDif = segundosDif / SEGUNDOS_PER_MINUTO;

		long segundos = segundosMod;

		long minutosMod = minutosDif % MINUTOS_PER_HORA;		

		long horasDif = minutosDif	/ MINUTOS_PER_HORA;
		
		long minutos = minutosMod;

		long horasMod = horasDif % HORAS_PER_DIA;

		long diasDif = horasDif / HORAS_PER_DIA;

		long horas = horasMod;

		long diasMod = diasDif % DIAS_PER_MES;

		long mesesDif = diasDif / DIAS_PER_MES;

		long dias = diasMod;

		long mesesMod = mesesDif % MESES_PER_YEAR;

		long yearDif = mesesDif / MESES_PER_YEAR;

		long mes = mesesMod;

		String tiempoAsignacion = "";

		if (yearDif > 0) {
			tiempoAsignacion += yearDif + " Año(s) ";
		}

		if (mes > 0 && mes < 12) {
			tiempoAsignacion += mes + " Mes(es) ";
		}

		if (dias > 0 && dias < 30) {
			tiempoAsignacion += dias + " Dia(s) ";
		}

		if (horas >= 0) {
			tiempoAsignacion += horas + " Hora(s) ";
		}
		
		if (minutos >= 0) {
			tiempoAsignacion += minutos + " Minuto(s) ";
		}
		
		if (segundos >= 0) {
			tiempoAsignacion += segundos + " Segundo(s) ";
		}

		return tiempoAsignacion;
	}

	public static BigDecimal avg(List<BigDecimal> input) {
		BigDecimal total = new BigDecimal("0");
		for (BigDecimal bigDecimal : input) {
			total = total.add(bigDecimal);
		}
		return total.divide(new BigDecimal(input.size() + ""));
	}
	
	public static String generateRandomKey(){
		return String.valueOf(System.currentTimeMillis());
	}
	
	
	public static boolean validateRFC(String input){
		return validateExpresion( input,"[A-Z,Ñ,&]{3,4}[0-9]{2}[0-1][0-9][0-3][0-9][A-Z,0-9]?[A-Z,0-9]?[0-9,A-Z]?" );
	}
	
	public static boolean validateMail(String input){
		return validateExpresion( input,"^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}$" );
	}
	
	public static boolean validateExpresion(String input,String expression ){
		boolean isValid = false;
		CharSequence inputStr = input;  
		//Make the comparison case-insensitive.  
		Pattern pattern = Pattern.compile(expression,Pattern.CASE_INSENSITIVE);  
		Matcher matcher = pattern.matcher(inputStr);  
		if(matcher.matches()){  
			isValid = true;  
		}  
		return isValid;   
	}
	
	public static boolean isNullOrEmpty(String s) {
		return s == null || s.isEmpty();
	}
	
	public static boolean isNullOrEmpty(Collection<?> c) {
		return c == null || c.isEmpty();
	}

	public static boolean isNullOrEmpty(Object[] array) {
		return array == null || array.length == 0;
	}

	private static final Date fechaActual = new Date();
	public static Date getFechaActual() {
		fechaActual.setTime(System.currentTimeMillis());
		return fechaActual;
	}

	//Formato de Fechas
	private static String ultimoFormato = "ddMMyyyy";
	private static final SimpleDateFormat FORMATO_FECHA_ESTANDAR = new SimpleDateFormat("dd/MM/yyyy");
	private static final SimpleDateFormat FORMATO_FECHA_ANIOMESDIA = new SimpleDateFormat("yyyyMMdd");
	private static final SimpleDateFormat FORMATO_FECHA_MEDIACION = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
	private static final SimpleDateFormat FORMATO_FECHA_COMPLETO = new SimpleDateFormat("dd/MMMM/yyyy hh:mm:ss.SSS a");
	private static final SimpleDateFormat FORMATO_FECHA_GENERICO = new SimpleDateFormat(ultimoFormato);

	/**
	 * Método estático para aplicar formato de fecha/hora al objeto Date introducido, permite ser sincronizado para utilizarse en multiples hilos.
	 * 
	 * @param fecha Date que contiene la fecha/hora a formatear.
	 * @param formato Objeto String del formato de fecha/hora que se quiere aplicar al objeto Date.
	 * 
	 * @return Retorna un String con la fecha en el formato aplicado.
	 */
	public static synchronized String formatDateToString(Date fecha, String formato) {
		if (formato.equals("dd/MM/yyyy")) {
			return FORMATO_FECHA_ESTANDAR.format(fecha);
		} else if (formato.equals("yyyyMMdd")) {
			return FORMATO_FECHA_ANIOMESDIA.format(fecha);
		} else if (formato.equals("dd/MMMM/yyyy hh:mm:ss.SSS a")) {
			return FORMATO_FECHA_COMPLETO.format(fecha).toUpperCase();
		} else {
			if (!formato.equals(ultimoFormato)) {
				FORMATO_FECHA_GENERICO.applyPattern(formato);
				ultimoFormato = formato;
			}
			return FORMATO_FECHA_GENERICO.format(fecha);
		}
	}

	/**
	 * Método estático para aplicar un formato de fecha/hora a la cadena
	 * introducida, permite ser sincronizado para utilizarse en multiples hilos.
	 * 
	 * @param fecha
	 *            String que contiene la fecha a parsear.
	 * @param formato
	 *            String que contiene el formato de fecha/hora que tiene el
	 *            parametro fecha.
	 * 
	 * @return Retorna un objeto Date con el valor requerido.
	 * @throws Exception
	 */
	public static synchronized Date parseStringToDate(String fecha, String formato) throws Exception {
		try {
			if (formato.equals("yyyy-MM-dd'T'HH:mm:ss")) {
				return FORMATO_FECHA_MEDIACION.parse(fecha);
			} else if (formato.equals("dd/MM/yyyy")) {
				return FORMATO_FECHA_ESTANDAR.parse(fecha);
			} else if (formato.equals("yyyyMMdd")) {
				return FORMATO_FECHA_ANIOMESDIA.parse(fecha);
			} else {
				if (!formato.equals(ultimoFormato)) {
					FORMATO_FECHA_GENERICO.applyPattern(formato);
					ultimoFormato = formato;
				}
				return FORMATO_FECHA_GENERICO.parse(fecha);
			}
		} catch (ParseException e) {
			throw new Exception("parseStringToDate(), java.text.ParseException al aplicar formato: " + formato + " a la fecha: " + fecha, e);
		}
	}
}